package bnetwork;

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

public class ClimateNetwork {

	private static final int SEASON_DOMAIN = 2;
	private static final int SENSING_DOMAIN = 2;
	private static final int ICE_DOMAIN = 2;
	private static final int CLIMATE_DOMAIN = 3;

	public static final int SUMMER = 0, WINTER = 1;
	public static final int WARM = 0, COLD = 1, FRIGID = 2;
	public static final int NO_ICE = 0, ICE = 1;
	public static final int SENSE_NONE = 0, SENSE_ICE = 1;

	Node season;
	Node[] climates;
	Node[] blocks;
	Node[] sensing1;
	Node[] sensing2;
	Map<Integer, Node[]> blocksMap;
	Map<Node, Integer> evidence;

	protected Region[] _regions;

	public ClimateNetwork(Region[] initRegions, ProbabilityPack p, int x, int y){
		//regionProbs[i]- for each region:
		//				{{summerWarm, summerCold, summerFrigid},
		//				 {winterWarm, winterCold, winterFrigid}};
		season = new Node("season", SEASON_DOMAIN, null, new float[][]{{p.summer, (1-p.summer)}});
//		regions = new Node[initRegions.length];
		int numBlocks = 0;
		for (int i=0; i<initRegions.length; i++){	//creating the regions
//			regions[i] = new Node("region"+(i+1),1,null,new float[][]{{1}});
			numBlocks = numBlocks + initRegions[i].getNumBlocks();
		}

		climates = new Node[initRegions.length];

		for (int i=0; i<initRegions.length; i++){
//			climates[i] = new Node("climate"+(i+1), CLIMATE_DOMAIN, new Node[]{season, regions[i]}, initRegions[i].getClimateProb());
			climates[i] = new Node("climate"+(i+1), CLIMATE_DOMAIN, new Node[]{season}, initRegions[i].getClimateProb());
			season.addChild(climates[i]);
		}

		//for each block - construct the icy patches with the initial probability
		//the sensing probability is unknown at the start
		float[][] iceDepsProto = new float[][]{
				{(1-p.warmIce), p.warmIce},					//warm climate
				{(1-p.coldIce), p.coldIce},					//cold climate
				{(1-p.frigidIce), p.frigidIce}};			//frigid climate
		float[][] closeSensorProto = new float[][]{
				{p.closeProb, (1-p.closeProb)},			//sensor says no ice
				{(1-p.closeProb), p.closeProb}};		//sensor says yes ice
		float[][] farSensorProto = new float[][]{
				{p.farProb, (1-p.farProb)},					//sensor says no ice
				{(1-p.farProb), p.farProb}};				//sensor says yes ice


		/* sensor|	yes	 | 	no	|
		 *    ice|-------|------|
		 * 	  yes|       |      |
		 *     no|       |      |
		 * ---------------------- */

		blocks = new Node[numBlocks];
		blocksMap = new TreeMap<Integer, Node[]>();
		sensing1 = new Node[numBlocks];
		sensing2 = new Node[numBlocks];
		int i=0;
		for (int k=0; k<initRegions.length; k++){
			for (Block b: initRegions[k].getBlocks()){
				float[][] probIce = null;
				if (b.isClose(x, y)){
					probIce = copyArr(closeSensorProto);
				} else {
					probIce = copyArr(farSensorProto);
				}
				blocks[i] = new Node("block"+b.getCell(), ICE_DOMAIN, new Node[]{climates[k]}, copyArr(iceDepsProto));
				sensing1[i] = new Node("sensing"+i+"#1", SENSING_DOMAIN, new Node[]{blocks[i]}, probIce);
				sensing2[i] = new Node("sensing"+i+"#2", SENSING_DOMAIN, new Node[]{blocks[i]}, copyArr(probIce));
				
				climates[k].addChild(blocks[i]);
				blocks[i].addChild(sensing1[i]);
				blocks[i].addChild(sensing2[i]);
				
				blocksMap.put(new Integer(b.getCell()), new Node[]{blocks[i], sensing1[i], sensing2[i]});
				i++;
			}
		}
		
		evidence = new HashMap<Node, Integer>();
	}

	public Node getSeason() {
		return season;
	}

	public Node[] getClimates() {
		return climates;
	}

	public Map<Integer, Node[]> getBlocks(){
		return blocksMap;
	}

	private static float[][] copyArr(float[][] org){
		float[][] ans = new float[org.length][];
		for (int i=0; i<org.length; i++){
			ans[i] = new float[org[i].length];
			for (int j=0; j<org[i].length; j++){
				ans[i][j] = org[i][j];
			}
		}
		return ans;
	}

	public int numOfBlocks() {
		return blocks.length;
	}

	public Node[] getBlockArr(int next) {
		return blocksMap.get(next);
	}

	public void enumerate() {
		season.enumerateAsk(evidence, season);
		for (Node n:climates){
			n.enumerateAsk(evidence, season);
		}
		for (Node n:blocks){
			n.enumerateAsk(evidence, season);
		}
		for (Node n:sensing1){
			n.enumerateAsk(evidence, season);
		}
		for (Node n:sensing2){
			n.enumerateAsk(evidence, season);
		}
		
	}

	public void addEvidence(Node n, int value) {
		evidence.put(n, value);
	}
	
	public void removeEvidence(Node n) {
		evidence.remove(n);
	}

	public boolean isEvidence(Node y) {
		return evidence.containsKey(y);
	}

	public float getProbIce(Map<Node, Integer> evidence, int node) {
		Node n = blocksMap.get(node)[0]; 
		n.enumerateAsk(evidence, season);
		return n.getProb(ICE);
	}

	public Map<Node, Integer> getEvidence() {
		return evidence;
	}

}
